﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Data;
using System.Collections;
using System.Text.RegularExpressions;

namespace WinnerCMS.WebControls
{
    [ToolboxData("<{0}:TagCloud runat=server></{0}:TagCloud>")]
    public class TagCloud : WebControl
    {

        #region "属性"


        #region "Appearance"

        [Bindable(true), Category("Appearance"), Localizable(true)]
        public int MinFontSize
        {
            get
            {
                string s = (string)ViewState["MinFontSize"];
                if (String.IsNullOrEmpty(s))
                    return 10;
                else
                {
                    int result = 10;
                    int.TryParse(s, out result);
                    return result;
                }
            }
            set
            {
                ViewState["MinFontSize"] = value;
            }
        }

        [Bindable(true), Category("Appearance"), Localizable(true)]
        public int MaxFontSize
        {
            get
            {
                string s = (string)ViewState["MaxFontSize"];
                if (String.IsNullOrEmpty(s))
                    return 22;
                else
                {
                    int result = 22;
                    int.TryParse(s, out result);
                    return result;
                }
            }
            set
            {
                ViewState["MaxFontSize"] = value;
            }
        }

        [Bindable(true), Category("Appearance"), Localizable(true)]
        public string FontUint
        {
            get
            {
                string s = (string)ViewState["FontUint"];
                if (String.IsNullOrEmpty(s))
                    return "pt";
                else
                    return s;
            }
            set
            {
                switch (value)
                {
                    case "pt":
                    case "em":
                    case "%":
                    case "px":
                        ViewState["FontUnit"] = value; break;
                    default:
                        ViewState["FontUnit"] = "px"; break;
                }
            }
        }

        [Bindable(true), Category("Appearance"), Localizable(true)]
        public string MaxColor
        {
            get
            {
                string s = (string)ViewState["MaxColor"];

                if (String.IsNullOrEmpty(s))
                    return "#00f";
                else
                    return s;
            }
            set
            {
                ViewState["MaxColor"] = value;
            }
        }

        [Bindable(true), Category("Appearance"), Localizable(true)]
        public string MinColor
        {
            get
            {
                string s = (string)ViewState["MinColor"];

                if (String.IsNullOrEmpty(s))
                    return "#000";
                else
                    return s;
            }
            set
            {
                ViewState["MinColor"] = value;
            }
        }

        #endregion

        #region "Data"

        [Bindable(true), Category("Data"), DefaultValue("")]
        public DataSet DataSource
        {
            get
            {
                return (DataSet)ViewState["DataSource"];
            }
            set
            {
                ViewState["DataSource"] = value;
            }
        }

        [Bindable(true), Category("Data"), DefaultValue(""), Localizable(true)]
        public string DataIDField
        {
            get
            {
                return (string)ViewState["DataIDField"];
            }
            set
            {
                ViewState["DataIDField"] = value;
            }
        }

        [Bindable(true), Category("Data"), DefaultValue(""), Localizable(true)]
        public string DataKeywordField
        {
            get
            {
                return (string)ViewState["DataKeywordField"];
            }
            set
            {
                ViewState["DataKeywordField"] = value;
            }
        }

        [Bindable(true), Category("Data"), DefaultValue(""), Localizable(true)]
        public string DataURLField
        {
            get
            {
                return (string)ViewState["DataURLField"];
            }
            set
            {
                ViewState["DataURLField"] = value;
            }
        }

        [Bindable(true), Category("Data"), DefaultValue(""), Localizable(true)]
        public string DataCountField
        {
            get
            {
                return (string)ViewState["DataCountField"];
            }
            set
            {
                ViewState["DataCountField"] = value;
            }
        }

        [Bindable(true), Category("Data"), Localizable(true)]
        public string KeywordTitleFormat
        {
            get
            {
                string s = (string)ViewState["KeywordTitleFormat"];
                if (String.IsNullOrEmpty(s))
                {
                    return "%k occured %c times";
                }
                else
                {
                    return (string)ViewState["KeywordTitleFormat"];
                }
            }
            set
            {
                ViewState["KeywordTitleFormat"] = value;
            }
        }

        [Bindable(true), Category("Data"), Localizable(true)]
        public string KeywordURLFormat
        {
            get
            {
                return (string)ViewState["KeywordURLFormat"];
            }
            set
            {
                ViewState["KeywordURLFormat"] = value;
            }
        }

        [Bindable(true), Category("Data"), DefaultValue(""), Localizable(true)]
        public string SortBy
        {
            get
            {
                return (string)ViewState["SortBy"];
            }
            set
            {
                ViewState["SortBy"] = value;
            }
        }

        #endregion

        [Bindable(false), Category("Debug"), DefaultValue(false), Localizable(true)]
        public Boolean Debug
        {
            get
            {
                if (ViewState["Debug"] != null)
                {
                    return (Boolean)ViewState["Debug"];
                }
                else
                {
                    return false;
                }

            }
            set
            {
                ViewState["Debug"] = value;
            }
        }


        #region Private Properties

        private Hashtable arrAttributes;

        private string CloudHTML
        {
            get
            {
                string s = (string)ViewState["CloudHTML"];
                if (String.IsNullOrEmpty(s))
                {
                    return string.Empty;
                }
                return s;
            }
            set
            {
                ViewState["CloudHTML"] = value;
            }
        }

        private Hashtable KeyAttributes
        {
            get
            {
                return arrAttributes;
            }
            set
            {
                arrAttributes = value;
            }
        }

        #endregion

        #endregion

        protected override void Render(HtmlTextWriter writer)
        {
            if (!String.IsNullOrEmpty(CloudHTML))
            {
                writer.WriteBeginTag("div");

                if (!String.IsNullOrEmpty(CssClass))
                {
                    writer.WriteAttribute("class", CssClass);
                }
                writer.Write(HtmlTextWriter.TagRightChar);
                writer.Write(CloudHTML);
                writer.WriteEndTag("div");
            }
            else
            {
                writer.Write("这儿没有产生HTML,一个未操作错误发生.");
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            if (DataSource == null)
            {
                CloudHTML = "请指定DataSet";
                return;
            }
            if (DataIDField .Length==0)
            {
                CloudHTML = "请指定一个ID数据段";
                return;
            }
            if (DataKeywordField.Length==0 )
            {
                CloudHTML = "请指定一个关键词数据段";
                return;
            }
            if (DataCountField .Length==0  )
            {
                CloudHTML = "请指定一个关键词数量数据段";
                return;
            }
            if (!Regex.IsMatch(MinColor, "^#([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?$"))
            {
                CloudHTML = "最小颜色必须为十六进制编码并且必须为如: #000 or #ff99cc";
                return;
            }
            if (!Regex.IsMatch(MaxColor, "^#([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?$"))
            {
                CloudHTML = "最小颜色必须为十六进制编码并且必须为如: #000 or #ff99cc";
                return;
            }

            try
            {
                StringBuilder sb = new StringBuilder();
                DataView dv = new DataView(DataSource.Tables[0]);
                //DataRowView row;

                dv.Sort = string.Format("{0} DESC", DataCountField);

                int count = dv.Count;

                if (count == 0)
                {
                    CloudHTML = "没有任何值产生云";
                    return;
                }

                int MaxQty = int.Parse(dv[0].Row[DataCountField].ToString());
                int MinQty = int.Parse(dv[dv.Count - 1].Row[DataCountField].ToString());

                int Spread = MaxQty - MinQty;

                if (Spread == 0)
                    Spread = 1;

                int FontSpread = MaxFontSize - MinFontSize;
                if (FontSpread == 0)
                    FontSpread = 1;

                double FontStep = (double)(FontSpread) / Spread;

                if (!string.IsNullOrEmpty(SortBy))
                {
                    dv.Sort = SortBy;
                }
                else
                {
                    dv.Sort = string.Format("{0} ASC", DataKeywordField);
                }

                foreach (DataRowView row in dv)
                {
                    int sKeyID = int.Parse(row.Row[DataIDField].ToString());
                    string sKeyWord = row.Row[DataKeywordField].ToString();
                    int sKeyCount = int.Parse(row.Row[DataCountField].ToString());
                    string sKeyURL;
                    string ColorRGB;
                    double Weight = MinFontSize + ((sKeyCount - MinQty) * FontStep);
                    int FontDiff = MaxFontSize - MinFontSize;
                    double ColorWeight = Math.Round(99 * (Weight - MinFontSize) / (FontDiff) + 1);

                    if (MinColor == MaxColor)
                    {
                        ColorRGB = MinColor;
                    }
                    else
                    {
                        ColorRGB = Colorize(MinColor, MaxColor, ColorWeight);
                    }

                    if (String.IsNullOrEmpty(DataURLField))
                    {
                        if (!String.IsNullOrEmpty(KeywordURLFormat))
                        {
                            sKeyURL = ReplaceKeyValues(KeywordURLFormat, sKeyID, sKeyWord, "", sKeyCount);
                        }
                        else
                        {
                            sKeyURL = "#";
                        }
                    }
                    else
                    {
                        sKeyURL = row[DataURLField].ToString();
                    }
                    sb.Append(string.Format("<a href=\"{0}\" style=\"font-size:{1}{5};color:{4};\" title=\"{2}\"{6}>{3}</a> ",
                        sKeyURL,
                        Math.Round(Weight),
                        ReplaceKeyValues(KeywordTitleFormat, sKeyID, sKeyWord, sKeyURL, sKeyCount),
                        HttpContext.Current.Server.HtmlEncode(sKeyWord),
                        ColorRGB,
                        FontUint,
                        GenerateAttributes(sKeyWord, sKeyID, sKeyURL, sKeyCount)));
                }
                CloudHTML = sb.ToString();
            }
            catch (Exception ex)
            {
                if (!Debug)
                {
                    CloudHTML = "错误产生";
                }
                else
                {
                    throw ex;
                }
            }
            finally
            {
                base.OnLoad(e);
            }
        }

        public void AddAttribute(string value, string text)
        {
            if (KeyAttributes == null)
            {
                KeyAttributes = new Hashtable();
            }
            KeyAttributes.Add(value, text);
        }

        private string GenerateAttributes(string k, int id, string u, int c)
        {
            if (KeyAttributes == null)
            {
                return string.Empty;
            }

            StringBuilder s = new StringBuilder();
            ICollection keys = KeyAttributes.Keys;

            foreach (object key in keys)
            {
                s.Append(string.Format(" {0}=\"{1}\"", key, ReplaceKeyValues(KeyAttributes[key].ToString(), id, k, u, c)));
            }

            return s.ToString();
        }

        private string ReplaceKeyValues(string txt, int id, string k, string u, int c)
        {
            k = k.Replace("'", "&apos;");

            txt = txt.Replace("%i", id.ToString());
            txt = txt.Replace("%k", HttpContext.Current.Server.HtmlEncode(k));
            txt = txt.Replace("%u", u);
            txt = txt.Replace("%c", c.ToString());

            return txt;
        }

        private string Colorize(string minc, string maxc, double w)
        {
            w = w / 100;
            string rs, gs, bs;
            string r, g, b;
            int minr, ming, minb, maxr, maxg, maxb;

            if (minc.Length == 4)
            {
                rs = minc.Substring(1, 1);
                gs = minc.Substring(2, 1);
                bs = minc.Substring(3, 1);

                minc = "#" + rs + rs + gs + gs + bs + bs;
            }

            if (maxc.Length == 4)
            {
                rs = maxc.Substring(1, 1);
                gs = maxc.Substring(2, 1);
                bs = maxc.Substring(3, 1);

                maxc = "#" + rs + rs + gs + gs + bs + bs;
            }

            minr = Convert.ToInt32(minc.Substring(1, 2), 16);
            ming = Convert.ToInt32(minc.Substring(3, 2), 16);
            minb = Convert.ToInt32(minc.Substring(5, 2), 16);

            maxr = Convert.ToInt32(maxc.Substring(1, 2), 16);
            maxg = Convert.ToInt32(maxc.Substring(3, 2), 16);
            maxb = Convert.ToInt32(maxc.Substring(5, 2), 16);

            r = Convert.ToString(int.Parse(Math.Round(((maxr - minr) * w) + minr).ToString()), 16);
            g = Convert.ToString(int.Parse(Math.Round(((maxg - ming) * w) + ming).ToString()), 16);
            b = Convert.ToString(int.Parse(Math.Round(((maxb - minb) * w) + minb).ToString()), 16);

            if (r.Length == 1)
                r = "0" + r;
            if (g.Length == 1)
                g = "0" + g;
            if (b.Length == 1)
                b = "0" + b;

            string color;
            color = "#" + r + g + b;

            return color;
        }
    }
}
